---
title: Optimistic Updates
sidebar_label: Optimistic Updates
---

# Optimistic Updates

Optimistic updates are a powerful UI pattern that can make your application feel significantly faster and more
responsive. The idea is to update the UI _immediately_ after a user action, assuming the server request will succeed. If
the request later fails, you simply roll back the UI to its previous state. This avoids making the user wait for the
network round-trip for actions like deleting an item or adding a comment.

:::secondary What you'll learn

1.  What **optimistic updates** are and why they improve user experience.
2.  How to implement optimistic updates using the **`useSubmit`** hook.
3.  How to use lifecycle callbacks like **`onSubmitRequestStart`** and **`onSubmitError`** to manage UI state.
4.  How to **roll back** UI changes if the server request fails.

:::

## Deleting an Item Optimistically

A common use case for optimistic updates is deleting an item from a list. The user clicks "Delete," the item disappears
instantly from the UI, and the delete request is sent in the background.

{/* Here's a live example of a user list where users can be deleted optimistically. */}

```tsx
function UserRow({ user, onListRevalidate }) {
  const [isDeleted, setIsDeleted] = React.useState(false);

  // highlight-start
  const { submit, submitting, onSubmitRequestStart, onSubmitError, onSubmitSuccess } = useSubmit(
    deleteUser.setParams({ userId: user.id }),
  );

  onSubmitRequestStart(() => {
    // Optimistically update the UI by hiding the row
    setIsDeleted(true);
  });

  onSubmitError(() => {
    // If the request fails, roll back the UI change
    setIsDeleted(false);
    alert(`Failed to delete ${user.name}.`);
  });

  onSubmitSuccess(() => {
    // On success, we can revalidate the user list to ensure consistency
    onListRevalidate();
  });
  // highlight-end

  if (isDeleted) {
    return null;
  }

  return (
    <tr>
      <td className="px-6 py-4 whitespace-nowrap">{user.name}</td>
      <td className="px-6 py-4 whitespace-nowrap">{user.email}</td>
      <td className="px-6 py-4 whitespace-nowrap">
        <button
          className="text-red-600 hover:text-red-800 disabled:text-gray-400"
          onClick={() => submit()}
          disabled={submitting}
        >
          {submitting ? "Deleting..." : "Delete"}
        </button>
      </td>
    </tr>
  );
}

function OptimisticUserList() {
  const { data: users, loading, error, revalidate } = useFetch(getUsers);

  if (loading) return <p className="p-4">Loading users...</p>;
  if (error) return <p className="p-4 text-red-500">Error loading users.</p>;

  return (
    <div className="border rounded-md">
      <table className="min-w-full divide-y divide-gray-200">
        <thead className="bg-gray-50">
          <tr>
            <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
              Name
            </th>
            <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
              Email
            </th>
            <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
              Action
            </th>
          </tr>
        </thead>
        <tbody className="bg-white divide-y divide-gray-200">
          {users?.map((user) => <UserRow key={user.id} user={user} onListRevalidate={revalidate} />)}
        </tbody>
      </table>
    </div>
  );
}
```

### How It Works

1.  The `UserRow` component manages its own optimistic state (`isDeleted`).
2.  We use `useSubmit` to get a `submit` function and lifecycle callbacks (`onSubmitRequestStart`, `onSubmitError`,
    `onSubmitSuccess`).
3.  **`onSubmitRequestStart`**: Before the request is sent, we set `isDeleted` to `true`. This immediately removes the
    row from the UI, creating the optimistic effect.
4.  **`onSubmitError`**: If the server returns an error, we revert the UI by setting `isDeleted` back to `false`. It's
    also good practice to inform the user that the action failed.
5.  **`onSubmitSuccess`**: If the request succeeds, the UI is already correct. We call `revalidate` (passed from the
    parent) on the original user list query to ensure our local data is perfectly in sync with the server.

This pattern makes for a great user experience, as the UI feels instantaneous.

---

:::success Congratulations!

You've learned how to implement optimistic updates in Hyper-fetch!

- You can use **lifecycle callbacks** from `useSubmit` to control UI state during a request.
- You can **optimistically update** your UI for a faster user experience.
- You know how to **roll back** changes on failure and **revalidate** data on success.

:::
